#include "axbopenglwidget.h"

unsigned int VAO, VBO, EBO;
float ratio = 0.9;

float vertices[] = {
     0.3f,  0.3f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,  // top right
     0.3f, -0.3f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,  // bottom right
    -0.3f, -0.3f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,  // bottom left
    -0.3f,  0.3f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f   // top left
};

unsigned int indices[] ={
    0, 1, 3,    // first triangle
    1, 2, 3     // second triangle
};

AXBOpenGLWidget::AXBOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{
    setFocusPolicy(Qt::StrongFocus);
    connect(&timer, SIGNAL(timeout()), this, SLOT(on_timeout()));
    timer.start(100);
}

AXBOpenGLWidget::~AXBOpenGLWidget()
{
    makeCurrent();
    glDeleteBuffers(1, &EBO);
    glDeleteBuffers(1, &VBO);
    glDeleteVertexArrays(1, &VAO);
    doneCurrent();
}

void AXBOpenGLWidget::drawShape(AXBOpenGLWidget::Shape shape)
{
    m_shape = shape;
    update();
}

void AXBOpenGLWidget::setWireframe(bool wireframe)
{
    makeCurrent();
    if (wireframe)
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    else
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    update();
    doneCurrent();
}

void AXBOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    // 创建渲染管线
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/shapes.vert");
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/shapes.frag");
    bool success = shaderProgram.link();
    if (!success)
        qDebug() << "ERR:" << shaderProgram.log();

    // 创建VAO、VBO和EBO对象,并赋予ID
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    // 绑定当前VAO、VBO和EBO
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

    // 设置缓冲区
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 告知显卡如何解析缓冲区里的属性值,索引为0
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    // 开启VAO管理的第0个属性值
    glEnableVertexAttribArray(0);

    // 告知显卡如何解析缓冲区里的属性值,索引为1
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    // 开启VAO管理的第1个属性值
    glEnableVertexAttribArray(1);

    // 告知显卡如何解析缓冲区里的属性值,索引为2
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    // 开启VAO管理的第2个属性值
    glEnableVertexAttribArray(2);

    // 设置复用顶点索引
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    textureWall = new QOpenGLTexture(QImage(":/Images/wall.png").mirrored());
    textureSmile = new QOpenGLTexture(QImage(":/Images/awesomeface.png").mirrored());
    textureSmall = new QOpenGLTexture(QImage(":/Images/small.png").mirrored());

    shaderProgram.bind();
    shaderProgram.setUniformValue("textureWall", 0);
    shaderProgram.setUniformValue("textureSmile", 1);
    shaderProgram.setUniformValue("textureSmall", 2);
    shaderProgram.setUniformValue("ratio", ratio);

    textureSmall->bind(2);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // 解除绑定VAO、VBO和EBO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

}

void AXBOpenGLWidget::resizeGL(int w, int h)
{
    Q_UNUSED(w);
    Q_UNUSED(h);
}

void AXBOpenGLWidget::paintGL()
{
    QMatrix4x4 matrix;
    unsigned int time = QTime::currentTime().msec();
    matrix.translate(0.5, -0.5, 0);
    matrix.rotate(time, 0.0f, 0.0f, 1.0f);

    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    shaderProgram.bind();
    glBindVertexArray(VAO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

    switch (m_shape) {
    case Rect:
        textureWall->bind(0);
        textureSmile->bind(1);
        textureSmall->bind(2);

        shaderProgram.setUniformValue("theMatrix", matrix);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        matrix.setToIdentity();
        matrix.translate(-0.5, 0.5, 0);
        matrix.scale(sin(time));
        shaderProgram.setUniformValue("theMatrix", matrix);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        break;
    default:
        break;
    }

}

void AXBOpenGLWidget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_Up:
        ratio += 0.1;
        break;
    case Qt::Key_Down:
        ratio -= 0.1;
        break;
    default:
        break;
    }
    if (ratio < 0) ratio = 0;
    if (ratio > 1) ratio = 1;

    makeCurrent();
    shaderProgram.bind();
    shaderProgram.setUniformValue("ratio", ratio);
    doneCurrent();
    update();
}

void AXBOpenGLWidget::on_timeout()
{
    update();
}

